home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Networking / Network Watch (DMZ) v1.5 / sources / dmzOT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-25  |  31.0 KB  |  1,156 lines  |  [TEXT/MPS ]

  1. /*
  2. #-------------------------------------------------------------------------------------------
  3. #
  4. #    Program:    < DMZ 1.5 >
  5. #    File:        < dmzOT.c >
  6. #    
  7. #    by Rich Kubota
  8. #    of <Apple Macintosh Developer Technical Support - or wheverever>
  9. #
  10. #    Modification History
  11. #    4/24/96  rrk    Added raw mode support under OT so that we can access the full DDP
  12. #                    header info - like the hop count field.  This technique also allows
  13. #                    one to fill out the DDP packet header themselves and have the packet
  14. #                    transmitted as is.  Unfortunately, this technique will not work for trying
  15. #                    to transmit a packet with a DDP type of 0.
  16. #
  17. #    6/14/94     rrk    Added OpenTransport support to DMZ
  18. #    
  19. #-------------------------------------------------------------------------------------------
  20. */
  21.  
  22. /*
  23.  *     dmz Sample OpenTransport Stuff
  24.  *
  25.  *    This unit provides OpenTansport AppleTalk support for dmz.  
  26.  *    These functions are similar to many of those provided in the dmzAT.c file.  
  27.  */
  28.  
  29. #include    "dmz.h"
  30.  
  31. // static globals here
  32. static ATSvcRef            gOTSvcRef    = nil;
  33. static MapperRef        gOTMapper    = nil;
  34. static EndpointRef        gOTEndpoint = nil;
  35. static OTNameID            gMyNameID    = 0;
  36. static UInt32            gNBPLookupOutstanding = 0;
  37. static TLookupRequest    gLookupRequest;
  38. static TLookupReply        gLookupReply;
  39.  
  40. static NBPEntity        gNBPEntity;
  41. static OTResult            gLookupResult;
  42.  
  43. static long                gNotifyFlag;
  44. static long                gStartTicks;
  45. static long                gEndTicks;
  46. static OTEventCode        gNotifyCode;
  47. static OSStatus            gNotifyErr;
  48. static void*            gOKAckMsg = NULL;
  49. static void*            gNotifyCookie;
  50. static OSStatus            gErrorAckMsg    = kOTNoError;
  51.  
  52.  
  53. /* globals from afar */
  54. /* out main dialog */
  55. extern DialogPtr         gLookupDialog;
  56. extern DialogPtr         gMyDialog;
  57. extern char             gNameGlob[34];
  58. extern SysEnvRec        GMAC;
  59. extern short            gATalkFlags;
  60.  
  61. // out of the dmzAT file
  62. extern PacketBuffer        gBuffers[kNumBuffers];    /* set up by InitEchoBuffers */
  63. extern QHdr                gFreeQ, gUsedQ;        /* set up by InitEchoBuffers */
  64. extern Handle             gSockCodeHndl;         /* handle to socket listener code resource */
  65. extern Ptr                 gBuffPtr;
  66. extern myMPPParamBlock     *gPBLkUP;
  67. extern Boolean             gUpdateListFlag;
  68. extern Boolean             gLookupFinished;
  69. extern NamesTableEntry     gMyNTE;
  70. extern AddrBlock         gTheBridgeAddress;
  71. extern Boolean            gHasPhase2;
  72.  
  73. extern Ptr                GTHEVBLPTR;
  74. extern Ptr                GTHETASKPTR;
  75.  
  76. // globals referenced from dmzLists.c
  77. extern ListHandle         gZonesList, gObjectTypeList;
  78.  
  79.  
  80. /************************* local prototypes *************************/
  81. static short    clen(char *cptr);
  82. static void        c2p(char *cptr);
  83. /********************************************************************/
  84. static OSStatus         DoBindDDPEndpoint(EndpointRef ep, DDPAddress *retAddr);
  85. static pascal void      HandleEndpointEvents(void* contextPtr, OTEventCode code,
  86.                                        OTResult result, void* it);
  87. static OSStatus          ReadData(EndpointRef ep, UInt8    *buffer, short buflen);
  88. static Boolean          CanDoRawMode(EndpointRef ep);
  89. static void                DoValueBreak(long value, const char* message);
  90.  
  91. /*
  92.  * CheckOpenTransportActive checks whether ASLM is available using
  93.  * InitLibraryManager.  If successful, then set the flag
  94.  * to indicate so
  95.  */ 
  96.  
  97. OSErr ActivateOpenTransport(void)
  98. {
  99.     OSErr        err;
  100.     OSStatus    oserr = kOTNoError;
  101.  
  102.     err = InitOpenTransport();
  103.  
  104.         // open the appletalk services provider
  105.     if (err == noErr)
  106.         gOTSvcRef = OTOpenAppleTalkServices(OTCreateConfiguration(kZIPName), 0, &oserr);
  107.     
  108.         // open an NBP Mapper service provider
  109.     if ((err == noErr) && (oserr == kOTNoError))
  110.         gOTMapper = OTOpenMapper(OTCreateConfiguration(kNBPName), 0, &oserr);
  111.         
  112.     if ((err == noErr) && (oserr == kOTNoError))
  113.     {
  114.             // install notifier for the mapper
  115.             // note that since OpenTransport sets the A5 world for a handler,
  116.             // we don't need to mess with saving/setting/restoring A5 - yea!!
  117.         oserr = OTInstallNotifier(gOTMapper, (OTNotifyProcPtr)MyDMZNBPHandler, nil);
  118.     }
  119.  
  120.         // open an endpoint ref 
  121.     if ((err == noErr) && (oserr == kOTNoError))
  122.     {
  123.         // set up the endpoint
  124.         gOTEndpoint = OTOpenEndpoint(OTCreateConfiguration(kDDPName), 0, nil, &oserr);
  125.         if (oserr == kOTNoError)
  126.         {
  127.             // install asynchronous notifier
  128.             OTInstallNotifier(gOTEndpoint, HandleEndpointEvents, &gNotifyFlag);
  129.         }
  130.     }
  131.             
  132.     if ((err == noErr) && (oserr == kOTNoError))
  133.     {                                        // if ASLM init'd ok, then the
  134.                                             // associated Open Transport libs were found
  135.         SetOTActiveFlag(gATalkFlags);    // indicate OpenTransport is active
  136.         gHasPhase2 = true;                    // we have phase 2
  137.     }
  138.     else        // error occurred somewhere
  139.     {    
  140.         if (gOTSvcRef)
  141.         {
  142.             OTCloseProvider(gOTSvcRef);
  143.             gOTSvcRef = nil;
  144.         }
  145.         if (gOTMapper)
  146.         {
  147.             OTCloseProvider(gOTMapper);
  148.             gOTMapper = nil;
  149.         }
  150.         if (gOTEndpoint)
  151.         {
  152.             OTCloseProvider(gOTEndpoint);
  153.             gOTEndpoint = nil;
  154.         }
  155.     }
  156.     
  157.     if (err != noErr)
  158.         return err;
  159.     else
  160.         return oserr;
  161. }
  162.  
  163. /*
  164.  * OpenTransportActive simplifies checking the global flag to see whether
  165.  * the OTActive flag is set.  This could also be a macro
  166.  */
  167.  
  168. Boolean OpenTransportActive(void)
  169. {
  170.     return (TstOTActiveFlag(gATalkFlags));
  171. }
  172.  
  173. /*
  174.  * GetBridgeAddressFromOT uses OpenTransport to determine whether
  175.  * there is a router on the network
  176.  */
  177.  
  178. typedef struct AppleTalkInfo AppleTalkInfo;
  179.  
  180. void GetBridgeAddressFromOT(AddrBlock *theAddr)
  181. {
  182.     AppleTalkInfo    info;
  183.     TNetbuf            reply;
  184.     OSErr            err;
  185.     
  186.         // set reply values
  187.     reply.buf = (UInt8*)&info;
  188.     reply.len = reply.maxlen = sizeof(info);
  189.     
  190.     err = OTATalkGetInfo(gOTSvcRef, &reply);
  191.     if (err != noErr)
  192.     {
  193.         DebugStr("\pError returned from OTATalkGetInfo");
  194.         theAddr->aNet = 0;
  195.         theAddr->aNode = 0;
  196.         theAddr->aSocket = 0;
  197.     }
  198.     else
  199.     {
  200.         theAddr->aNet = info.fRouterAddress.fNetwork;
  201.         theAddr->aNode = info.fRouterAddress.fNodeID;
  202.         theAddr->aSocket = info.fRouterAddress.fSocket;
  203.     }
  204. }
  205.  
  206. /*
  207.  * DoOTGetMyZone uses OpenTransport to determine what
  208.  * the current zone is
  209.  */
  210. void DoOTGetMyZone(char *myZoneBuffer)
  211. {
  212.     TNetbuf        reply;
  213.     OSErr        err;
  214.  
  215.     reply.buf = (UInt8*)myZoneBuffer;
  216.     //reply.len = 0;
  217.     reply.maxlen = sizeof(Str32);
  218.     err = OTATalkGetMyZone(gOTSvcRef, &reply);
  219.     if (err != noErr)
  220.         myZoneBuffer[0] = 0;
  221. }
  222.  
  223. /*
  224.  * DoOTGetZoneList uses OpenTransport to determine whether
  225.  * there is a router on the network
  226.  */
  227. void DoOTGetZoneList(void)
  228. {
  229.     TNetbuf        reply;
  230.     OSErr        err = 0;
  231.     Ptr            unpackedBufferPtr, packedBufferPtr;
  232.     short        numZones;
  233.     
  234.         // need two buffers to hold the zone names
  235.         // 1 to give to the OTZoneList call to fill in a packed list of zone names
  236.         // 2 to unstuff the zones names and pass to the SetZoneCells call
  237.     packedBufferPtr = NewPtr(kMaxZoneBuffSize);     /* size of maxstring size * 255 zones */
  238.     unpackedBufferPtr = NewPtr(kMaxZoneBuffSize);     /* size of maxstring size * 255 zones */
  239.     if (packedBufferPtr != nil && unpackedBufferPtr != nil)
  240.     {
  241.         reply.buf = (UInt8*)packedBufferPtr;
  242.         reply.maxlen = kMaxZoneBuffSize;        // under OT, the buffer for the zone names can be greater than 32767
  243.                                                 // however since we are passing the buffer to the List Manager
  244.                                                 // we limit the size to max SInt16
  245.     
  246.             // set service ref for synch mode
  247.         OTSetSynchronous(gOTSvcRef);
  248.         
  249.         err = OTATalkGetZoneList(gOTSvcRef, &reply);
  250.         
  251.         if (err != kOTNoError && err != kOTNoDataErr)
  252.             BigBadError("\pOTGetZoneList returned err - Aborting program!!");
  253.         else
  254.         {
  255.                 // unpack the zone names into the unpackedBuffer
  256.             numZones = addToOTUnpackedBuffer(packedBufferPtr, unpackedBufferPtr, reply.len);
  257.                 // set the zone names in the zone cells
  258.             SetZoneCells(unpackedBufferPtr, numZones);
  259.         }
  260.     }
  261.     else
  262.     {
  263.         BigBadError("\pError getting memory for GetZoneList call - Aborting program!!");
  264.     }
  265.     
  266.         
  267. }
  268.  
  269. void CleanupOTServices(void)
  270. {
  271.         // close AppleTalk Services
  272.     OTCloseProvider(gOTSvcRef);
  273.         // close the mapper
  274.     OTCloseProvider(gOTMapper);
  275.         // close the endpoint
  276.     OTCloseProvider(gOTEndpoint);
  277.     ClrOTLookupActiveFlag(gATalkFlags);        // clear the OTActive flag
  278. }
  279.  
  280.  
  281. /*
  282.  *    in order for us to use the standard qsort() algorithm, our data must be alligned in
  283.  *    an orderly fashion with a set offset from each data entry. This routine takes care of
  284.  *    that through simple _BlockMove manipulations.  Note that this routine is a modification
  285.  *  of the addToUnpackedBuffer routine in that it assumes that all of the names are in
  286.  *  the unpacked buffer.  Instead of the number of zones, we only know the number of
  287.  *  valid bytes in the buffer.  We also determine the number of zones and return this 
  288.  *    info to the caller.
  289.  */
  290. short addToOTUnpackedBuffer(Ptr packedBuffer, Ptr unpackedBuffer, long len)
  291. {
  292.     long    index = 0L;
  293.     short    i = 0;
  294.     
  295.     while ((index < len) && (index < kMaxZoneBuffSize - 32))
  296.     {
  297.         BlockMove((Ptr)packedBuffer+index, (Ptr)unpackedBuffer+i*33, 33L);
  298.         index += (char)((Ptr)packedBuffer+index)[0]+1L;
  299.         i++;
  300.     }
  301.     return i;
  302. }
  303.  
  304. /*******************************************************************************
  305. ** Register my name using Open Transport
  306. ********************************************************************************/
  307. void OTRegisterMyName (void)
  308. {
  309.     TRegisterRequest regreq;
  310.     TRegisterReply        regreply;
  311.     StringHandle    userNameHndl;
  312.     OSErr        err;
  313.     UInt8        nameBuf[100];
  314.     
  315.         // for registering a name, we'll first try to get the flagship name
  316.         // otherwise, we'll use the machinename
  317.     userNameHndl = GetString(kFlagshipNameResourceID);
  318.     if (**userNameHndl == 0) 
  319.     {
  320.         userNameHndl = GetString(kMachineNameResourceID); 
  321.         if(**userNameHndl == 0)
  322.         {
  323.             userNameHndl = (StringHandle)NewHandle(32);
  324.             if (userNameHndl)
  325.                 BlockMove("\pYour name here.", *userNameHndl, 15L);
  326.         }
  327.         
  328.     }
  329.         // create the NBP name string and set the len field for the string
  330.     regreq.name.len = OTMySetNBPEntity((char*)nameBuf, (Ptr)*userNameHndl, (Ptr)kEchoType, (Ptr)"\p*");
  331.     regreq.name.maxlen = sizeof(nameBuf);
  332.     regreq.name.buf = nameBuf;
  333.     
  334.         // let the system define the network address for this name
  335.     regreq.addr.len = regreq.addr.maxlen = 0;
  336.     regreq.addr.buf = NULL;
  337.     
  338.         // set up regreply
  339.     regreply.addr.maxlen = 0;
  340.     regreply.addr.buf = nil;
  341.         
  342.     OTSetSynchronous(gOTMapper);
  343.     err = OTRegisterName(gOTMapper, ®req, ®reply);
  344.     gMyNameID = regreply.nameid;
  345. }
  346.  
  347. /*******************************************************************************
  348. ** Delete my name using Open Transport
  349. ********************************************************************************/
  350. void OTDeleteMyName (void)
  351. {    
  352.     OTSetSynchronous(gOTMapper);
  353.     OTDeleteNameByID(gOTMapper, gMyNameID);    
  354. }
  355.  
  356. /*******************************************************************************
  357. ** HandleMapperEvents TMapper (NBP) Event Handling
  358. ********************************************************************************/
  359.  
  360. pascal void MyDMZNBPHandler(void* contextPtr, OTEventCode event, OTResult result, void* cookie)
  361. {
  362.  
  363.     switch (event)
  364.     {
  365.         case T_LKUPNAMERESULT:        // intermediate result notification
  366.             break;
  367.             
  368.         case T_LKUPNAMECOMPLETE:
  369.             gUpdateListFlag = true;
  370.                 // clear bit which indicates that we are doing a lookup
  371.             ClrOTLookupActiveFlag(gATalkFlags);
  372.             break;
  373.             
  374.         case T_REGNAMECOMPLETE:
  375.             if (result == kOTNoError)
  376.             {
  377.                 SetNameRegisteredFlag(gATalkFlags);
  378.                     /* if error occured registering name, there is no reason to 
  379.                      * abort the program 
  380.                      */
  381.             }
  382.             break;
  383.             
  384.         case T_DELNAMECOMPLETE:
  385.             if (result == kOTNoError)
  386.             {
  387.                 ClrNameRegisteredFlag(gATalkFlags);
  388.             }
  389.             break;
  390.             
  391.         default:
  392.             DebugStr("\pHandleMapperEvents: Unexpected Event!;g");
  393.             break;
  394.     }
  395. }
  396.  
  397. UInt16 OTMySetNBPEntity(char *buffer, Ptr nbpObject, Ptr nbpType, Ptr nbpZone)
  398. {
  399.     char*    bufPtr;
  400.     UInt16    len;
  401.     
  402.     bufPtr = buffer;
  403.  
  404.     BlockMove((Ptr)&nbpObject[1], bufPtr, nbpObject[0]);
  405.     bufPtr += nbpObject[0];        // point buffer to end of current string
  406.     len = nbpObject[0];            // collect number of chars moved to buffer
  407.  
  408.         // add the ":" character between the object and type strings
  409.     *bufPtr = ':';
  410.     bufPtr++;
  411.     len++;
  412.  
  413.     BlockMove((Ptr)&nbpType[1], bufPtr, nbpType[0]);
  414.     bufPtr += nbpType[0];        // point buffer to end of current string
  415.     len += nbpType[0];            // collect number of chars moved to buffer
  416.     
  417.         // add the "@" character between the type and zone strings
  418.     *bufPtr = '@';
  419.     bufPtr++;
  420.     len++;
  421.  
  422.     BlockMove((Ptr)&nbpZone[1], bufPtr, nbpZone[0]);
  423.     len += nbpZone[0];            // collect number of chars moved to buffer
  424.     return len;    
  425. }
  426.  
  427. void DoOTNameLookup(char *NBPObject, char *NBPType, char *NBPZone)
  428. {
  429.     OSErr    err;
  430.     
  431.         // first check to see whether a Lookup is in progress
  432.     if (TstOTLookupActiveFlag(gATalkFlags))
  433.         return;
  434.  
  435.         // set the maximum number of names to match
  436.     gLookupRequest.maxcnt = kLookupBufSize / kNBPEntityBufferSize;
  437.         // set the timeout paramter in milliseconds
  438.     gLookupRequest.timeout = 8000;        // 8 seconds
  439.         // set the name to look up
  440.  
  441.     gLookupRequest.name.len = (size_t)OTMySetNBPEntity((char*)&gNBPEntity, (Ptr)NBPObject, (Ptr)NBPType, (Ptr)NBPZone);
  442.     // gLookupRequest.name.maxlen = gLookupRequest.name.len;
  443.     gLookupRequest.name.buf = (UInt8*)&gNBPEntity;
  444.     
  445.     gLookupRequest.addr.len = 0;
  446.     gLookupRequest.addr.maxlen = 0;
  447.     gLookupRequest.addr.buf = nil;
  448.     
  449.     gLookupReply.names.maxlen = kLookupBufSize;
  450.  
  451.     memset(gBuffPtr, 0, kLookupBufSize);    // zero out the buffer so that extraneous characters don't get left 
  452.                                             // in the buffer to confuse the name parsing routines which are looking
  453.                                             // for null terminated strings.
  454.     gLookupReply.names.buf = (UInt8*)gBuffPtr;
  455.     
  456.         // indicate that we are doing a lookup
  457.     gLookupFinished = false;
  458.         // start spinning cursor
  459.     StartAnimatedCursors(kSpinEvery5Ticks, 15);
  460.     
  461.         // make the call asynchronously
  462.     OTSetAsynchronous(gOTMapper);
  463.     err = OTLookupName(gOTMapper, &gLookupRequest, &gLookupReply);
  464.         // indicate that a lookup call is active.
  465.     SetOTLookupActiveFlag(gATalkFlags);
  466.  
  467. }
  468.  
  469. void    ProcessOTListUpdate(char *resultStr)
  470. {
  471.     Str255    errorStr;
  472.     
  473.     if (gLookupResult == noErr)
  474.     {
  475.         NumToString((long)gLookupReply.rspcount, (StringPtr)resultStr);
  476.         Pstrcat((StringPtr)resultStr, "\p items");
  477.         
  478.             // set the cells of the list
  479.         OTSetObjectTypeCells(gBuffPtr, gLookupReply.rspcount);
  480.     }
  481.     else
  482.     {
  483.         NumToString((long)gLookupResult, errorStr);
  484.         resultStr[0] = 0;
  485.         Pstrcat((StringPtr)resultStr, "\pError ID = ");
  486.         Pstrcat((StringPtr)resultStr, errorStr);
  487.     }
  488.     StopAnimatedCursors();
  489. }
  490.  
  491. void OTSetObjectTypeCells(Ptr ptr, short numDevicesGot)
  492. {
  493.     DDPNBPAddress        *theNBPAddrInfo;
  494.     NBPEntity            *nbpEntity;
  495.     Cell                 theCell;
  496.     short                 ignore;
  497.     short                 numDevicesIndex;
  498.     short                maxCells;
  499.     GrafPtr             tp;
  500.     AddrBlock             *address;
  501.     UInt32                offset;
  502.     UInt16                addrLen, nameLen, totalLen;
  503.     
  504.     unsigned char        charHolder[6];
  505.     long                g;
  506.     myNetworkEntity     myNetEnt;
  507.     Ptr                    newBuffer;
  508.     UInt8                delimiter;
  509.     char                tempStr[10];
  510.     
  511.     /* tell the user this may take a little while... */
  512.     /*waitAWhile = GetCursor(watchCursor);
  513.     SetCursor(*waitAWhile);*/
  514.     
  515.     GetPort(&tp);
  516.     SetPort(gMyDialog);
  517.  
  518.     /* make room for as many objects as we need */
  519.     newBuffer = NewPtr(numDevicesGot*sizeof(myNetworkEntity));
  520.     if(newBuffer == 0L)
  521.         return;
  522.         
  523.     LDelRow(0, 0, gObjectTypeList);    /* deletes lists's cells */
  524.     
  525.     LSetDrawingMode(false, gObjectTypeList);  /* turn drawing off */
  526.     
  527.     numDevicesIndex = 0;
  528.         
  529.         // since the List Manager will only allow 32K entries, we need to limit the number
  530.         // of entries that can be entered - numDevicesGot may be just too large, so we take
  531.         // only those first n entries in the list which will fit into the list
  532.     maxCells = numDevicesGot < (32767 / (sizeof(myNetworkEntity) + 4)) ? numDevicesGot : (32767 / (sizeof(myNetworkEntity) + 4)); 
  533.  
  534.     while(numDevicesIndex<maxCells) 
  535.     {
  536.         SpinTheCursor();
  537.         theCell.v = numDevicesIndex;
  538.         
  539.         ignore = LAddRow(1, numDevicesIndex, gObjectTypeList);    
  540.  
  541.             // get the address and name lengths
  542.         addrLen = ((short*)ptr)[0];
  543.         nameLen = ((short*)ptr)[1];
  544.         
  545.             // set theAddr to point to the beginning of the DDPNBP structure
  546.         theNBPAddrInfo = (DDPNBPAddress*)(ptr + 2 * sizeof(short));
  547.         
  548.             // set address to point to the appropriate spot in the address buffer
  549.         address = (AddrBlock*)&theNBPAddrInfo->fNetwork;
  550.         
  551.         /* first move address data into "hidden" cell */
  552.         theCell.h = 1;
  553.         LSetCell((Ptr) address, 4, theCell, gObjectTypeList);
  554.         
  555.             // set the nbpEntity pointer to point to the namebuffer
  556.         nbpEntity = (NBPEntity*)&theNBPAddrInfo->fNBPNameBuffer;
  557.  
  558.         /* now move object name & type into one cell */
  559.         theCell.h = 0;
  560.         
  561.         /* object */
  562.             // extract the object name from the entity which is a null terminated
  563.             // string with the object, type, and zone name separated by the 
  564.             // ':' and '@' characters.  Call OTExtractNBPCName which is a routine
  565.             // defined here to parse the entity up to the character specified as the
  566.             // delimiter.  The offset parameter is 0 and is passed in to indicate that
  567.             // we want to parse the object field from the beginning of the entity.
  568.         delimiter = ':';
  569.         offset = OTExtractNBPCName(nbpEntity, (char *)&myNetEnt.object, 0, &delimiter);
  570.             // the name is in c string style, convert to pascal
  571.         c2p((char *)&myNetEnt.object);
  572.             // make sure that the string length is no longer than 32 chars
  573.         if(myNetEnt.object[0] > 32)
  574.             myNetEnt.object[0] = 32;
  575.             
  576.         /* type */
  577.             // we do the same for the type string as we did for the object name
  578.             // above.
  579.         delimiter = '@';
  580.         OTExtractNBPCName(nbpEntity, (char *)&myNetEnt.type, offset, &delimiter);
  581.             // the name is in c string style, convert to pascal
  582.         c2p((char *)&myNetEnt.type);
  583.             // make sure that the string length is no longer than 32 chars
  584.         if(myNetEnt.type[0] > 32)
  585.             myNetEnt.type[0] = 32;
  586.         
  587.         /* network */
  588.         g = (long)address->aNet;
  589.         g = g & 0x0000FFFF; /* mask out hiword crap */
  590.         NumToString(g, (void *) &charHolder);
  591.         padEntry((void *) &charHolder, 5, rightJust);
  592.         BlockMove(&charHolder, &myNetEnt.net, 6L);
  593.  
  594.         /* node */
  595.         NumToString((long)address->aNode, (void *) &charHolder);
  596.         padEntry((void *) &charHolder, 3, rightJust);
  597.         BlockMove(&charHolder, &myNetEnt.node, 4L);
  598.     
  599.         /* socket */
  600.         NumToString((long)address->aSocket, (void *) &charHolder);
  601.         padEntry((void *) &charHolder, 3, rightJust);
  602.         BlockMove(&charHolder, &myNetEnt.socket, 4L);
  603.                 
  604.         BlockMove((Ptr) &myNetEnt, (Ptr)newBuffer+(numDevicesIndex)*sizeof(myNetworkEntity), 
  605.             sizeof(myNetworkEntity));
  606.  
  607.         LSetCell((Ptr)&myNetEnt, sizeof(myNetworkEntity), theCell, gObjectTypeList);    
  608.             
  609.             // increment the index counter
  610.         numDevicesIndex += 1; 
  611.             // get the total length of this NBP record
  612.         totalLen = addrLen + nameLen + 2 * sizeof(short);
  613.             // advance the ptr to the next record which is alligned on a 4 byte
  614.             // boundary
  615.         ptr = ptr + ((totalLen + 3) & ~3);
  616.             
  617.         }
  618.  
  619.     /* do a quicksort() on the mess */
  620.     letsSort(newBuffer, numDevicesGot, sizeof(myNetworkEntity));
  621.     
  622.     numDevicesIndex = 0;
  623.     
  624.     while(numDevicesIndex<maxCells) 
  625.     {
  626.         theCell.v = numDevicesIndex;
  627.         theCell.h = 0;
  628.         BlockMove((Ptr)newBuffer+(numDevicesIndex)*sizeof(myNetworkEntity), (Ptr) &myNetEnt, sizeof(myNetworkEntity));
  629.         LSetCell((Ptr)&myNetEnt, sizeof(myNetworkEntity), theCell, gObjectTypeList);    
  630.         numDevicesIndex += 1;
  631.     }
  632.         
  633.     DisposePtr(newBuffer);
  634.     
  635.     NumToString(numDevicesIndex, (void *) tempStr);
  636.  
  637.     ParamText((ConstStr255Param)tempStr, "\p# of objects: ", "\p", "\pOT active");
  638.     
  639.     LSetDrawingMode(true, gObjectTypeList);
  640.     invalidateItem(8);
  641.     invalidateItem(2);
  642.  
  643.     SetPort(tp);
  644.     InitCursor();
  645. }
  646.  
  647. /*****************************************************************************/
  648. /* Convert a c-string to a pascal-string. */
  649. short    clen(char *cptr)
  650. {
  651.     short    i;
  652.  
  653.     for (i = 0; cptr[i]; ++i) {};
  654.     return(i);
  655. }
  656.  
  657. /*****************************************************************************/
  658. void    c2p(char *cptr)
  659. {
  660.     char    len;
  661.  
  662.     BlockMove(cptr, cptr + 1, len = clen(cptr));
  663.     *cptr = len;
  664. }
  665.  
  666. /*****************************************************************************/
  667.  
  668. /*
  669.  *    doOTEcho is the Open Transport version of the doEcho call.  It is 
  670.  *    called when the user double clicks on some item indicating
  671.  *  to send an echo packet to the echo socket on the node of that item.
  672.  *    Note that we don't use an Assembler socket listener
  673.  *
  674.  *    Addition as of 4/24/96 - implemented the use of raw mode for sending out data so that
  675.  *    we get the return data in rawmode.  This allows us to get the DDP header info.
  676.  *    Under rawmode, you create the entire packet and become responsible for sending out
  677.  *  the entire packet.  
  678.  *
  679.  *  WARNING: You must ensure that the unitdata.data.len field never exceeds 599
  680.  *  else, OT will never send the packet.
  681.  */
  682. void doOTEcho(myNetworkEntity    *myEnt)
  683. {
  684.     DDPAddress        retAddr, ddpAddr;
  685.     KeyMap            kk;
  686.     Rect            r;
  687.     TUnitData        unitdata;
  688.     Ptr                myRawBuffer = nil;
  689.     long            myWaitTicks;
  690.     DialogPtr        echoDialog;
  691.     Handle            h;
  692.     GrafPtr            savedPort;
  693.     
  694.     long            tempL;
  695.     OSStatus        err = kOTNoError;
  696.     OTResult        result;
  697.     
  698.     UInt16            rawDataSize;
  699.     UInt16            numHops;
  700.     
  701.     RawDPPPacketPtr    rawddpPtr;
  702.  
  703.     short            itemHit;
  704.     short            kind;
  705.     
  706.     UInt8            recvBuf[ddpMaxRawData+1];
  707.     Str255            str;
  708.     
  709.     char            noHopStr[2] = "\p?";
  710.     
  711. /*
  712.     the following are OTData related stuff
  713. */
  714.     OTData            otdata[3];
  715.     
  716.     UInt8            buf1[64] = "\001This is a sample string to send as the first part of the buffer";
  717.                             ///123456789012345678901234567890123456789012345678901234567890123
  718.     UInt8            buf2[64] = "This is a another sample string to send as the first part buffer";
  719.  
  720.     Boolean            gotEcho = false;
  721.     Boolean            epBound = false;
  722.     Boolean            done = false;
  723.     Boolean            useRawMode;
  724.         
  725.     GetPort(&savedPort);
  726.  
  727.         // set up the ddpAddr structure of the node which we want to
  728.         // send our echo test packet to.
  729.     ddpAddr.fAddressType = AF_ATALK_DDP;
  730.     
  731.         // set the network number
  732.     StringToNum((StringPtr) myEnt->net, (long *) &tempL);
  733.     ddpAddr.fNetwork = tempL;
  734.     
  735.         // set the node number
  736.     StringToNum((StringPtr) myEnt->node, (long *) &tempL);
  737.     ddpAddr.fNodeID = tempL;
  738.     
  739.         // set the socket field to the echo socket
  740.     ddpAddr.fSocket = 4;
  741.  
  742.         // indicate that the packet is an echo DDP packet
  743.     ddpAddr.fDDPType = 4;
  744.     
  745.         // get the dialog which we use to display the results
  746.     echoDialog = GetNewDialog(131, 0L, (WindowPtr) -1L);
  747.     SetPort(echoDialog);
  748.     
  749.     TextFont(geneva);
  750.     TextSize(9);
  751.     
  752.     setupEchoDialog(echoDialog, myEnt);
  753.  
  754.         // Bind shall be handled synchronously.
  755.     OTSetSynchronous(gOTEndpoint);
  756.     
  757.     
  758.     if (err == kOTNoError)
  759.     {
  760.             // get the current endpoint state
  761.         result = OTGetEndpointState(gOTEndpoint);
  762.         if (result == T_UNBND)
  763.         {
  764.                 // set up the reqAddr to point to the local echo socket
  765.             err = DoBindDDPEndpoint(gOTEndpoint, &retAddr);
  766.     
  767.             if (err != kOTNoError)
  768.             {
  769.                 GetDialogItem(echoDialog, 6, &kind, &h, &r);
  770.                 SetDialogItemText(h, "\pWah… Bind error occurred #");
  771.             }
  772.             else
  773.                 epBound = true;
  774.         }
  775.     }
  776.  
  777.         // check if the endpoint supports the raw mode so that we get the header info along with the
  778.         // datagram
  779.     useRawMode = CanDoRawMode(gOTEndpoint);
  780.     
  781.         // use rawmode unless the user has held down the option key
  782.     if (useRawMode == true)
  783.     {
  784.         GetKeys(kk);
  785.         if ((kk[1] & 0x0004) == true)
  786.         
  787.             useRawMode = false;
  788.     }
  789.         
  790.     if (useRawMode == true)
  791.     {
  792.             // allocate a buffer to send message
  793.         myRawBuffer = NewPtr(sizeof(RawDDPPacket));
  794.         if (myRawBuffer == nil)
  795.         {
  796.             GetDialogItem(echoDialog, 6, &kind, &h, &r);
  797.             SetDialogItemText(h, "\pWah… Out of mem error");
  798.             err = memFullErr;
  799.         }
  800.         else
  801.         {
  802.             rawddpPtr = (RawDPPPacketPtr)myRawBuffer;
  803.                 // use the following to specify the maimum packet size
  804.                 // the problem is that if you declare an array of 599 bytes, the size of function
  805.                 // returns 600 which will result in the packet never being sent.
  806.             rawDataSize = sizeof(RawDDPPacket) > ddpMaxRawData ? ddpMaxRawData : sizeof(RawDDPPacket);
  807.         }
  808.     }
  809.     
  810.             
  811.     if (err == kOTNoError)
  812.     {
  813.             // send shall be handled asynchronously.
  814.         OTSetAsynchronous(gOTEndpoint);
  815.         if (useRawMode == true)
  816.         {
  817.             //
  818.             //    packet length
  819.             //
  820.             rawddpPtr->data[0] = (UInt8)(rawDataSize >> 8) & 0x0003;    // clear hopcount, but set the upper 2 bits of the lenth
  821.             rawddpPtr->data[1] = (UInt8)(rawDataSize & 0x00FF);
  822.             //
  823.             //    packet checksum
  824.             //
  825.             rawddpPtr->data[2] = 0;        // no checksum
  826.             rawddpPtr->data[3] = 0;        // no checksum
  827.             //
  828.             //    dest network
  829.             //
  830.             rawddpPtr->data[4] = (UInt8)(ddpAddr.fNetwork >> 8);
  831.             rawddpPtr->data[5] = (UInt8)(ddpAddr.fNetwork & 0x00FF);
  832.             //
  833.             //    src network
  834.             //
  835.             rawddpPtr->data[6] = (UInt8)(retAddr.fNetwork >> 8);
  836.             rawddpPtr->data[7] = (UInt8)(retAddr.fNetwork & 0x00FF);
  837.  
  838.             rawddpPtr->data[8] = (UInt8)ddpAddr.fNodeID;        // dest node
  839.             rawddpPtr->data[9] = (UInt8)retAddr.fNodeID;        // src node
  840.             
  841.             rawddpPtr->data[10] = (UInt8)ddpAddr.fSocket;        // set dest socket to echo socket
  842.             rawddpPtr->data[11] = (UInt8)retAddr.fSocket;        // src socket
  843.             
  844.             rawddpPtr->data[12] = (UInt8)ddpAddr.fDDPType;    // set packet type to echo packet
  845.             
  846.             BlockMove((Ptr)&buf1, (Ptr)&rawddpPtr->data[13], sizeof(buf1));
  847.             
  848.                 // set up the unitdata structure
  849.             unitdata.udata.buf = (UInt8*)myRawBuffer;            // data area
  850.             unitdata.udata.len = rawDataSize;
  851.             unitdata.addr.buf = nil;        // address area    
  852.             unitdata.addr.len = (size_t)0xffffffffUL;
  853.             unitdata.opt.buf = nil;
  854.             unitdata.opt.len = 0;                         // no options being sent
  855.             
  856.         }
  857.         else
  858.         {
  859.             // demonstrate use of kNetbufDataIsOTData use of buffers
  860.         
  861.             // set up the OTData[0] structure
  862.             otdata[0].fNext = &otdata[1];
  863.             otdata[0].fData = &buf1;
  864.             otdata[0].fLen = sizeof(buf1);
  865.             
  866.             // set up the OTData[1] structure
  867.             otdata[1].fNext = &otdata[2];
  868.             otdata[1].fData = &buf2;
  869.             otdata[1].fLen = sizeof(buf2);
  870.             
  871.             // set up the OTData[2] structure - the end of the list
  872.             otdata[2].fNext = nil;
  873.             otdata[2].fData = nil;
  874.             otdata[2].fLen = 0;
  875.  
  876.                 // set up unitdata fields
  877.             unitdata.udata.buf = (UInt8*)otdata;            // data area
  878.             unitdata.udata.len = kNetbufDataIsOTData;
  879.             unitdata.addr.buf = (UInt8*)&ddpAddr;        // address area    
  880.             unitdata.addr.len = kDDPAddressLength;
  881.             unitdata.opt.len = 0;                         // no options being sent
  882.         }
  883.             
  884.         
  885.         result = OTDontAckSends(gOTEndpoint);
  886.         gNotifyCode = 0;
  887.         
  888.         gEndTicks = 0;
  889.         gStartTicks = TickCount();            /* start the timer! */
  890.         
  891.         err = OTSndUData(gOTEndpoint, &unitdata);
  892.         StartAnimatedCursors(kSpinEvery5Ticks, 15);
  893.         
  894.         myWaitTicks = TickCount() + 300L;    /* wait 5 seconds for reply */
  895.         
  896.         result = OTDontAckSends(gOTEndpoint);
  897.         if (err != kOTNoError)
  898.         {
  899.             GetDialogItem(echoDialog, 6, &kind, &h, &r);
  900.             SetDialogItemText(h, "\pWah… Send error occurred #");
  901.         }
  902.         
  903.         if (err == kOTNoError)
  904.         {
  905.             //
  906.             // It's very important that we read the data while we are waiting for the "ack send" to complete.
  907.             // DDP can use our own message to reply to us, and if we don't "read" the message, the "ackSend"
  908.             // will never complete.
  909.             //
  910.             while ((done == false) && (myWaitTicks > TickCount()))
  911.             {
  912.                 if ( gNotifyCode == T_DATA )
  913.                 {
  914.                     gNotifyCode = 0;
  915.                      while ( ReadData(gOTEndpoint, (UInt8*)&recvBuf, ddpMaxRawData) != kOTNoDataErr )
  916.                     {
  917.                         OTIdle();
  918.                         SpinTheCursor();
  919.                     }
  920.                     done = true;
  921.                 }
  922.                 SpinTheCursor();
  923.                 OTIdle();
  924.             }
  925.             
  926.             if (gEndTicks != 0)
  927.             {
  928.             
  929.                 GetDialogItem(echoDialog, 4, &kind, &h, &r);
  930.                 if (useRawMode == true)
  931.                 {
  932.                         // if we sent the outgoing packet using raw mode, then the incoming packet will
  933.                         // be returned in raw mode.
  934.                     rawddpPtr = (RawDPPPacketPtr)&recvBuf;
  935.                     numHops = ((UInt8)rawddpPtr->data[0] & 0x3C) >> 2;
  936.                     NumToString(numHops, (void *) &str);
  937.                     SetDialogItemText(h, str);
  938.                 }
  939.                 else                    
  940.                     SetDialogItemText(h, (ConstStr255Param)noHopStr);
  941.                 
  942.                 GetDialogItem(echoDialog, 5, &kind, &h, &r);
  943.                 NumToString(gEndTicks - gStartTicks, (void *) &str);
  944.                 SetDialogItemText(h, str);
  945.  
  946.             }
  947.             else
  948.             {
  949.                 GetDialogItem(echoDialog, 6, &kind, &h, &r);
  950.                 SetDialogItemText(h, "\pWah… no echo reply received!");
  951.             }
  952.         }
  953.     }
  954.  
  955.     StopAnimatedCursors();
  956.     if (epBound == true)
  957.     {
  958.         err = OTUnbind(gOTEndpoint);
  959.     }
  960.         
  961.     /* clean up memory allocations */
  962.     if (myRawBuffer != nil)
  963.         DisposePtr(myRawBuffer);
  964.     
  965.     /* report the results */
  966.     centerDialog((WindowPtr) echoDialog);
  967.  
  968.     InitCursor();
  969.     ShowWindow(echoDialog);
  970.     
  971.     ModalDialog(0L, &itemHit);
  972.     DisposeDialog(echoDialog);
  973.     
  974.     SetPort(savedPort);
  975. }
  976.  
  977. /*******************************************************************************
  978. ** DoBindEchoEndpoint - binds the passed endpoint ref to a DDP endpoint
  979.     the bound address is returned in the structure pointed to by the retAddr
  980.     parameter
  981. ********************************************************************************/
  982. OSStatus DoBindDDPEndpoint(EndpointRef ep, DDPAddress *retAddr)
  983. {
  984.     DDPAddress        reqAddr;
  985.     TBind            req, ret;
  986.     OSStatus        err = kOTNoError;
  987.  
  988.         // set up the reqAddr to point to the local echo socket
  989.     reqAddr.fAddressType = AF_ATALK_DDP;
  990.     reqAddr.fNetwork = 0;        // set to our network
  991.     reqAddr.fNodeID = 0;        // set to our node
  992.     reqAddr.fSocket = 0;        // bind to a dynamic socket
  993.     reqAddr.fDDPType = 0;        // accept all packets to our socket;
  994.         // bind the endpoint to the Echo socket
  995.     req.addr.buf = (UInt8*)&reqAddr;
  996.     req.addr.len = kDDPAddressLength;
  997.     req.qlen = 0;
  998.         // set up the return DDPAddress parameter if we are interested.
  999.         // in this sample, we don't use this information
  1000.     ret.addr.buf = (UInt8*)retAddr;
  1001.     ret.addr.maxlen = sizeof(DDPAddress);
  1002.     
  1003.     err = OTBind(ep, &req, &ret);
  1004.     
  1005.     return err;
  1006.  
  1007. }
  1008.  
  1009. /*******************************************************************************
  1010. ** HandleEndpointEvents
  1011. ********************************************************************************/
  1012.  
  1013. static pascal void  HandleEndpointEvents(void* contextPtr, OTEventCode code,
  1014.                                        OTResult result, void* it)
  1015. {
  1016.     switch (code)
  1017.     {            
  1018.         case T_DATA:
  1019.                 // set flag that some data has come in
  1020.             gNotifyCode = code;
  1021.             if ((gEndTicks == 0))
  1022.             {
  1023.                 gEndTicks = TickCount();
  1024.             }
  1025.             break;
  1026.         
  1027.         case T_GETINFOCOMPLETE:
  1028.         case T_LISTEN:
  1029.         case T_CONNECT:
  1030.         case T_EXDATA:
  1031.         case T_DISCONNECT:
  1032.         case T_ORDREL:
  1033.         case T_GODATA:
  1034.         case T_GOEXDATA:
  1035.         case T_REQUEST:
  1036.         case T_REPLY:
  1037.         case T_PASSCON:
  1038.         case T_RESET:
  1039.         case T_MEMORYRELEASED:
  1040.         case T_UNBINDCOMPLETE:
  1041.                 // do nothing
  1042.             break;
  1043.         
  1044.         
  1045.         default:
  1046.             DoValueBreak(code, "unknown event occurred: #");
  1047.             break;
  1048.     }
  1049.  
  1050. }
  1051.  
  1052. /*******************************************************************************
  1053. ** ReadData
  1054. ********************************************************************************/
  1055.  
  1056. static OSStatus ReadData(EndpointRef ep, UInt8    *buffer, short buflen)
  1057. {
  1058.     OTFlags            flags = 0;
  1059.     DDPAddress        theDest;
  1060.     TUnitData        theData;
  1061.     OSStatus         err;
  1062.     
  1063.     theData.udata.buf    = buffer;
  1064.     theData.udata.maxlen= buflen;
  1065.     theData.addr.buf    = (UInt8*)&theDest;
  1066.     theData.addr.maxlen    = sizeof(theDest);
  1067.     theData.opt.maxlen    = 0;
  1068.     
  1069.     err = OTRcvUData(ep, &theData, &flags);
  1070.     
  1071.     if ( err != kOTNoError )
  1072.         return err;
  1073.             
  1074.     return err;
  1075. }
  1076.  
  1077. /*
  1078.     CanDoRawMode gets the endpoint info and checks whether the T_CAN_SUPPORT_MDATA bit is
  1079.     set in the endpoint info flag field and returns true if so, false otherwise.
  1080. */
  1081. Boolean CanDoRawMode(EndpointRef ep)
  1082. {
  1083.     TEndpointInfo    info;
  1084.     OSStatus        err;
  1085.     Boolean            result;
  1086.     
  1087.     err = OTGetEndpointInfo(ep, &info);
  1088.     if (err != kOTNoError)
  1089.         result = false;
  1090.     else if (info.flags & T_CAN_SUPPORT_MDATA)
  1091.         result = true;        // this also means that the src addr info is in the info record
  1092.     else
  1093.         result = false;
  1094.  
  1095.     return result;
  1096. }
  1097.  
  1098.  
  1099. void DoValueBreak(long value, const char* message)
  1100. {
  1101.     static short    sDoErrorBreak = 0;
  1102.  
  1103.     {
  1104.         Str255    s,
  1105.                 n = "\p";
  1106.  
  1107.         s[0] = strlen(message);
  1108.         BlockMoveData(message,&s[1],s[0]);
  1109.         if (value < 0)
  1110.         {
  1111.             s[0] += 1;
  1112.             s[s[0]] = '-';
  1113.             value = -value;
  1114.         }
  1115.         while (value)
  1116.         {
  1117.             if (n[0])
  1118.                 BlockMoveData(&n[1],&n[2],n[0]);
  1119.             n[0]++;
  1120.             n[1] = 48 + (value % 10);
  1121.             value /= 10;
  1122.         }
  1123.         BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1124.         s[0] += n[0];
  1125.  
  1126.         sDoErrorBreak++;
  1127.         {
  1128.             short    cnt = sDoErrorBreak;
  1129.  
  1130.             s[0]++;
  1131.             s[s[0]] = ',';
  1132.             s[0]++;
  1133.             s[s[0]] = ' ';
  1134.             n[0] = 0;
  1135.             while (cnt)
  1136.             {
  1137.                 if (n[0])
  1138.                     BlockMoveData(&n[1],&n[2],n[0]);
  1139.                 n[0]++;
  1140.                 n[1] = 48 + (cnt % 10);
  1141.                 cnt /= 10;
  1142.             }
  1143.             BlockMoveData(&n[1],&s[s[0]+1],n[0]);
  1144.             s[0] += n[0];
  1145.         }
  1146. #ifdef    powerpc
  1147.         SysBreakStr(s);
  1148. #else
  1149.         DebugStr(s);
  1150. #endif
  1151.     }
  1152. }
  1153.  
  1154.  
  1155.  
  1156.